#ifndef caloriepanel_h
#define caloriepanel_h

#include "UtilityPanel.h"
#include <math.h>

class CaloriePanel : public UtilityPanel
{
private:
	/* All these constants come from http://www.freedieting.com/tools/calorie_calculator.htm */
	/* Minimum safe number of calories to consume per day */
	static const int MIN_CALORIES_MALE = 1500;
	static const int MIN_CALORIES_FEMALE = 1200;

	/* Maximum safe and preferred differences from maintenance calorie count */
	static const int MAX_CALORIE_DELTA = 1000;
	static const int PREFERRED_CALORIE_DELTA = 500;

	/* Maximum weight delta per week, in kilograms */
	static const float MAX_WEIGHT_DELTA = 1;

	/*
	 * Number of calories per kilogram of fat.
	 * Calculated from calories per pound from http://www.weightlossforall.com/calories-per-pound.htm
	 * Used 1kg = 2.2lbs and 3500cal per pound.
	 */
	static const int CALORIES_PER_KILO = 7700;

	enum {
		STANDARD, METRIC, MALE, FEMALE, CALCULATE,
	};

	TextField* ageField;
	TextField* weightDeltaField;
	TextField* heightField;
	TextField* weightField;
	UtilityButton* calcButton;
	SelectableUtilityButton* standard;
	SelectableUtilityButton* metric;
	SelectableUtilityButton* male;
	SelectableUtilityButton* female;

	int age;
	float weight;
	float height;
	float weightDelta;

	String calorieText;

	/*
	 * Calculate daily calories based on height, weight, and
	 * desired weekly weight gain/loss.
	 *
	 * Requires height in centimetres, weight in kilograms, age in years and gender.
	 *
	 * Returns an integer value which is the number of calories to consume
	 * daily to maintain current weight.
	 */
	int getBMR()
	{
		if(height < 0 || weight < 0)
		{
			std::cerr << "Height: " << height << "; Weight: " << weight << std::endl;
			return -1;
		}

		float cal = (9.99 * weight) + (6.25 * height) - (4.92 * age);

		if(male->isSelected())
		{
			cal += 5;
			if(cal < MIN_CALORIES_MALE)
			{
				std::cerr << cal << " is too low, adjusting to " << MIN_CALORIES_MALE << std::endl;
				cal = MIN_CALORIES_MALE;
			}
		}
		else if(female->isSelected())
		{
			cal -= 161;
			if(cal < MIN_CALORIES_FEMALE)
			{
				std::cerr << cal << " is too low, adjusting to " << MIN_CALORIES_FEMALE << std::endl;
				cal = MIN_CALORIES_FEMALE;
			}
		}
		else
		{
			std::cerr << "No gender chosen!" << std::endl;
			return -1;
		}

		return (int)(cal * 1.2);
	}
public:
	CaloriePanel() : UtilityPanel(T("Calorie Calculator"))
	{
		age = -1;
		height = -1;
		weight = -1;
		calorieText = String(T(" -- "));

		standard = new SelectableUtilityButton(STANDARD, this, T("Standard"));
		metric = new SelectableUtilityButton(METRIC, this, T("Metric"));
		male = new SelectableUtilityButton(MALE, this, T("Male"));
		female = new SelectableUtilityButton(FEMALE, this, T("Female"));

		ageField = new TextField(T("Age: "));
		heightField = new TextField(T("Height: "));
		weightField = new TextField(T("Weight: "));
		weightDeltaField = new TextField(T("Weight Change: "));
		calcButton = new UtilityButton(CALCULATE, this, T("Calculate"));

		metric->setSelected(true);

		addAndMakeVisible(ageField);
		addAndMakeVisible(heightField);
		addAndMakeVisible(weightField);
		addAndMakeVisible(weightDeltaField);
		addAndMakeVisible(calcButton);
		addAndMakeVisible(standard);
		addAndMakeVisible(metric);
		addAndMakeVisible(male);
		addAndMakeVisible(female);
	}

	~CaloriePanel()
	{
		delete ageField;
		delete heightField;
		delete weightField;
		delete weightDeltaField;
		delete standard;
		delete metric;
		delete calcButton;
		delete male;
		delete female;
	}

	void paintPanel(Graphics& g)
	{
		String heightUnit(metric->isSelected() ? T("m") : T("in"));
		String weightUnit(metric->isSelected() ? T("kg") : T("lb"));
		String weightDeltaUnit(metric->isSelected() ? T("kg/wk") : T("lb/wk"));

		g.setColour(Colours::lightgrey);
		g.drawHorizontalLine((int)(0.09 * getHeight()), getHeight() * 0.05, getWidth() - (getHeight() * 0.05));
		g.drawHorizontalLine((int)(0.21 * getHeight()), getHeight() * 0.05, getWidth() - (getHeight() * 0.05));
		g.drawHorizontalLine((int)(0.63 * getHeight()), getHeight() * 0.05, getWidth() - (getHeight() * 0.05));

		g.setColour(Colours::black);
		g.setFont(Font(Font::getDefaultSansSerifFontName(), 16, Font::plain));
		g.drawSingleLineText(heightUnit, heightField->getRight() + 3, heightField->getY() + heightField->getHeight() / 2 + 4);
		g.drawSingleLineText(weightUnit, weightField->getRight() + 3, weightField->getY() + weightField->getHeight() / 2 + 4);
		g.drawSingleLineText(weightDeltaUnit, weightDeltaField->getRight() + 3, weightDeltaField->getY() + weightDeltaField->getHeight() / 2 + 4);

		g.drawFittedText(calorieText, 0, (int)(0.7 * getHeight()), (int)(getWidth()), (int)(getHeight() - 0.8 * getHeight()), Justification::centred, 1);
	}

	void resized()
	{
		int buttonWidth = (int)(getWidth() - 0.3 * getWidth()) / 2;

		ageField->setBounds((int)(getWidth() * 0.1), (int)(getHeight() * 0.36), (int)(getWidth() - 0.35 * getWidth()), (int)(getHeight() * 0.06));
		heightField->setBounds((int)(getWidth() * 0.1), (int)(getHeight() * 0.42), (int)(getWidth() - 0.35 * getWidth()), (int)(getHeight() * 0.06));
		weightField->setBounds((int)(getWidth() * 0.1), (int)(getHeight() * 0.48), (int)(getWidth() - 0.35 * getWidth()), (int)(getHeight() * 0.06));
		weightDeltaField->setBounds((int)(getWidth() * 0.1), (int)(getHeight() * 0.54), (int)(getWidth() - 0.35 * getWidth()), (int)(getHeight() * 0.06));

		metric->setBounds((int)(getWidth() * 0.1), (int)(0.12 * getHeight()), buttonWidth, (int)(0.06 * getHeight()));
		standard->setBounds((int)(getWidth() * 0.55), (int)(0.12 * getHeight()), buttonWidth, (int)(0.06 * getHeight()));

		male->setBounds((int)(getWidth() * 0.1), (int)(0.24 * getHeight()), buttonWidth, (int)(0.06 * getHeight()));
		female->setBounds((int)(getWidth() * 0.55), (int)(0.24 * getHeight()), buttonWidth, (int)(0.06 * getHeight()));

		calcButton->setBounds((int)(getWidth() * 0.1), (int)(getHeight() * 0.67), (int)(getWidth() - 0.2 * getWidth()), (int)(getHeight() * 0.06));
	}

	void buttonClicked(int buttonID) {
		if(STANDARD == buttonID) {
			standard->setSelected(true);
			metric->setSelected(false);
		}
		else if(METRIC == buttonID)
		{
			standard->setSelected(false);
			metric->setSelected(true);
		}
		else if(MALE == buttonID)
		{
			male->setSelected(true);
			female->setSelected(false);
		}
		else if(FEMALE == buttonID)
		{
			male->setSelected(false);
			female->setSelected(true);
		}
		else if(CALCULATE == buttonID) {
			int bmr;
			int cal;

			age = (int)ageField->getValue();
			weight = weightField->getValue();
			height = heightField->getValue();
			weightDelta = weightDeltaField->getValue();

			/* Are we dealing in metric or Imperial? */
			if(metric->isSelected())
			{
				height *= 100;	/* Convert m to cm */
			}
			else if(standard->isSelected())
			{
				height *= 2.54;				/* Convert inches to cm */
				weight /= 2.2;		/* Convert pounds to kg */
				weightDelta /= 2.2;	/* Convert pounds to kg */
			}

			/* Make sure the weight change is safe */
			if(abs(weightDelta) > MAX_WEIGHT_DELTA)
			{
				if(metric->isSelected())
				{
					calorieText = String(T("Max safe: 1kg/wk"));
				}
				else if(standard->isSelected())
				{
					calorieText = String(T("Max safe: 2lb/wk"));
				}
			}
			else
			{
				bmr = getBMR();
				cal = bmr;
				/* Adjust for desired weight change if valid */
				if(-1 != cal)
				{
					cal += (int)(weightDelta * CALORIES_PER_KILO / 7);
					if(male->isSelected())
					{
						if(cal < MIN_CALORIES_MALE)
						{
							cal = MIN_CALORIES_MALE;
						}
					}
					else if(female->isSelected())
					{
						if(cal < MIN_CALORIES_FEMALE)
						{
							cal = MIN_CALORIES_FEMALE;
						}
					}

					/* Make sure the difference is still safe */
//					if(abs(bmr - cal) > MAX_CALORIE_DELTA)
//					{
//						if(weightDelta < 0)
//						{
//							cal = bmr - MAX_CALORIE_DELTA;
//						}
//						else if(weightDelta > 0)
//						{
//							cal = bmr + MAX_CALORIE_DELTA;
//						}
//					}
					male->isSelected() || female->isSelected() ? calorieText = String(cal) + T("cal") : calorieText = String(T("Choose a gender!"));
				}
			}
		}
		repaint();
	}
};

#endif
